/*****************************************************************************
#
#
******************************************************************************/
#include "EPD_2in9b_Z94.h"
#include "DEBUG.h"
// #include "EPD_SDCard.h"

#define DEBUG Debug
/******************************************************************************
function :	Software reset
parameter:
******************************************************************************/
static void EPD_2IN9B_Z94_Reset(void)
{
    // DEV_Digital_Write(EPD_RST_PIN, 1);
    // DEV_Delay_ms(10);
    DEV_Digital_Write(EPD_RST_PIN, 0);
    DEV_Delay_ms(10);
    DEV_Digital_Write(EPD_RST_PIN, 1);
    DEV_Delay_ms(10);
}

/******************************************************************************
function :	send command
parameter:
     Reg : Command register
******************************************************************************/
static void EPD_2IN9B_Z94_SendCommand(UBYTE Reg)
{
    DEV_Digital_Write(EPD_DC_PIN, 0);
    // DEV_Digital_Write(EPD_CS_PIN, 0);
    DEV_SPI_WriteByte(Reg);
    // DEV_Digital_Write(EPD_CS_PIN, 1);
}

/******************************************************************************
function :	send data
parameter:
    Data : Write data
******************************************************************************/


static void EPD_2IN9B_Z94_SendData(UBYTE Data)
{
    DEV_Digital_Write(EPD_DC_PIN, 1);
    // DEV_Digital_Write(EPD_CS_PIN, 0);
    DEV_SPI_WriteByte(Data);
    // DEV_Digital_Write(EPD_CS_PIN, 1);
}

static void EPD_2IN9B_Z94_SendData2(UBYTE *Data,UDOUBLE length)
{
    DEV_SPI_WriteByte(Data,length);
}

static void EPD_2IN9B_Z94_SendData2(UBYTE Data)
{
    // DEV_Digital_Write(EPD_DC_PIN, 1);
    // DEV_Digital_Write(EPD_CS_PIN, 0);
    DEV_SPI_WriteByte(Data);
    // DEV_Digital_Write(EPD_CS_PIN, 1);
}

/******************************************************************************
function :	Wait until the busy_pin goes LOW
parameter:
******************************************************************************/
static void EPD_2IN9B_Z94_ReadBusy(void)
{
    DEBUG("e-Paper busy\r\n");
    while (1)
    {
        if (DEV_Digital_Read(EPD_BUSY_PIN) == 0)
            break;
        DEV_Delay_ms(10);
    }

    DEBUG("e-Paper busy release\r\n");
}

void EPD_2IN9B_Z94_ReadBusy(uint32_t ms)
{
    Debug("e-Paper busy:%d\r\n",millis());
    for (uint32_t i = 0; i < ms; i += 10)
    {
        if (!DEV_Digital_Read(EPD_BUSY_PIN))
        {
            Debug("e-Paper busy release:%d\r\n",millis());
            return;
        }
        DEV_Delay_ms(10);
    }
    Debug("e-Paper busy timeout:%d\r\n",millis());
    
}

/******************************************************************************
function :	Initialize the e-Paper register
parameter:
******************************************************************************/
void EPD_2IN9B_Z94_Init(void)
{

    EPD_2IN9B_Z94_Reset();

    EPD_2IN9B_Z94_ReadBusy(100);
    EPD_2IN9B_Z94_SendCommand(0x12); // SWRESET
    EPD_2IN9B_Z94_ReadBusy(100);

    EPD_2IN9B_Z94_SendCommand(0x01); // Driver output control
    EPD_2IN9B_Z94_SendData((EPD_2IN9B_Z94_HEIGHT - 1) % 256);
    EPD_2IN9B_Z94_SendData((EPD_2IN9B_Z94_HEIGHT - 1) / 256);
    EPD_2IN9B_Z94_SendData(0x00);

    EPD_2IN9B_Z94_SendCommand(0x11); // data entry mode
    EPD_2IN9B_Z94_SendData(0x03);

    EPD_2IN9B_Z94_SendCommand(0x44); // set Ram-X address start/end position
    EPD_2IN9B_Z94_SendData(0x00);
    EPD_2IN9B_Z94_SendData(EPD_2IN9B_Z94_WIDTH / 8 - 1);

    EPD_2IN9B_Z94_SendCommand(0x45); // set Ram-Y address start/end position
    EPD_2IN9B_Z94_SendData(0x00);
    EPD_2IN9B_Z94_SendData(0x00);
    EPD_2IN9B_Z94_SendData((EPD_2IN9B_Z94_HEIGHT - 1) % 256);
    EPD_2IN9B_Z94_SendData((EPD_2IN9B_Z94_HEIGHT - 1) / 256);

    EPD_2IN9B_Z94_SendCommand(0x3C); // BorderWavefrom
    EPD_2IN9B_Z94_SendData(0x05);

    EPD_2IN9B_Z94_SendCommand(0x21); //  Display update control
    EPD_2IN9B_Z94_SendData(0x00);
    EPD_2IN9B_Z94_SendData(0x80);

    EPD_2IN9B_Z94_SendCommand(0x18); // Read built-in temperature sensor
    EPD_2IN9B_Z94_SendData(0x80);

    EPD_2IN9B_Z94_SendCommand(0x4E); // set RAM x address count to 0;
    EPD_2IN9B_Z94_SendData(0x00);
    EPD_2IN9B_Z94_SendCommand(0x4F); // set RAM y address count to 0X199;
    EPD_2IN9B_Z94_SendData(0x00);
    EPD_2IN9B_Z94_SendData(0x00);
    // EPD_2IN9B_Z94_SendData((EPD_2IN9B_Z94_HEIGHT - 1) % 256);
    // EPD_2IN9B_Z94_SendData((EPD_2IN9B_Z94_HEIGHT - 1) / 256);
    EPD_2IN9B_Z94_ReadBusy(100);
}

/******************************************************************************
function :	Clear screen
parameter:
******************************************************************************/
void EPD_2IN9B_Z94_Clear(void)
{
    UDOUBLE Width, Height;
    Width = (EPD_2IN9B_Z94_WIDTH % 8 == 0) ? (EPD_2IN9B_Z94_WIDTH / 8) : (EPD_2IN9B_Z94_WIDTH / 8 + 1);
    Height = EPD_2IN9B_Z94_HEIGHT;

    unsigned int i;
    EPD_2IN9B_Z94_SendCommand(0x24); // write RAM for black(0)/white (1)
    for (i = 0; i < Width * Height; i++)
    {
        EPD_2IN9B_Z94_SendData(0xFF);
    }
    EPD_2IN9B_Z94_SendCommand(0x26); // write RAM for black(0)/white (1)
    for (i = 0; i < Width * Height; i++)
    {
        EPD_2IN9B_Z94_SendData(0x00);
    }
    EPD_2IN9B_Z94_SendCommand(0x22); // Display Update Control
    EPD_2IN9B_Z94_SendData(0xF7);
    EPD_2IN9B_Z94_SendCommand(0x20); // Activate Display Update Sequence
    EPD_2IN9B_Z94_ReadBusy(15*1000); //9s
}

/******************************************************************************
function :	Sends the image buffer in RAM to e-Paper and displays
parameter:
******************************************************************************/
void EPD_2IN9B_Z94_Display(unsigned char *BW_Image, unsigned char *R_Image)
{
    UDOUBLE Width, Height;
    Width = (EPD_2IN9B_Z94_WIDTH % 8 == 0) ? (EPD_2IN9B_Z94_WIDTH / 8) : (EPD_2IN9B_Z94_WIDTH / 8 + 1);
    Height = EPD_2IN9B_Z94_HEIGHT;

    // send black data
    EPD_2IN9B_Z94_SendCommand(0x24);
    for (UDOUBLE j = 0; j < Height; j++)
    {
        for (UDOUBLE i = 0; i < Width; i++)
        {
            EPD_2IN9B_Z94_SendData(BW_Image[i + j * Width]);
        }
    }

    // send red data
    EPD_2IN9B_Z94_SendCommand(0x26);
    for (UDOUBLE j = 0; j < Height; j++)
    {
        for (UDOUBLE i = 0; i < Width; i++)
        {
            EPD_2IN9B_Z94_SendData(R_Image[i + j * Width]);
        }
    }

    EPD_2IN9B_Z94_SendCommand(0x22); // Display Update Control
    EPD_2IN9B_Z94_SendData(0xF7);
    EPD_2IN9B_Z94_SendCommand(0x20); // Activate Display Update Sequence
    EPD_2IN9B_Z94_ReadBusy(15*1000);
}

/******************************************************************************
function :	Enter sleep mode
parameter:
******************************************************************************/
void EPD_2IN9B_Z94_Sleep(void)
{
    EPD_2IN9B_Z94_SendCommand(0x10); // enter deep sleep
    EPD_2IN9B_Z94_SendData(0x01);
    DEV_Delay_ms(100);
}

/******************************************************************************
function :	Turn On Display
parameter:
******************************************************************************/
void EPD_2IN9B_Z94_TurnOnDisplay(void)
{
    EPD_2IN9B_Z94_SendCommand(0x22); // Display Update Control
    EPD_2IN9B_Z94_SendData(0xF7);
    EPD_2IN9B_Z94_SendCommand(0x20); // Activate Display Update Sequence
    EPD_2IN9B_Z94_ReadBusy(15*1000);
}

/******************************************************************************
function :	Sends the image buffer in RAM to e-Paper and displays
parameter:  color:black,0;red,1;*data;index;length
******************************************************************************/
void EPD_2IN9B_Z94_Data_Write(UBYTE color, UBYTE *Image_Data, UDOUBLE index, UDOUBLE length)
{
    if (index == 0)
    {
        if (color == 0)
        {
            EPD_2IN9B_Z94_SendCommand(0x24);
        }
        else if (color == 1)
        {
            EPD_2IN9B_Z94_SendCommand(0x26);
        }
        DEV_Digital_Write(EPD_DC_PIN, 1);
    }

    UDOUBLE Width, Height;
    Width = (EPD_2IN9B_Z94_WIDTH % 8 == 0) ? (EPD_2IN9B_Z94_WIDTH / 8) : (EPD_2IN9B_Z94_WIDTH / 8 + 1);
    Height = EPD_2IN9B_Z94_HEIGHT;

    // if(length==(Width*Height))
    // {
    //     for (UDOUBLE j = 0; j < Height; j++)
    //     {
    //         for (UDOUBLE i = 0; i < Width; i++)
    //         {
    //             EPD_2IN9B_Z94_SendData(Image_Data[i + (Height-j) * Width]);
    //         }
    //     }

    // }
    // else{
#ifdef EPD_SPI_ENABLE    
    EPD_2IN9B_Z94_SendData2(Image_Data,length);
#else
    for (UDOUBLE i = 0; i < length; i++)
    {
        if (color == 0)
        {
            // DEV_Digital_Write(EPD_DC_PIN, 1);
            // DEV_Digital_Write(EPD_CS_PIN, 0);
            EPD_2IN9B_Z94_SendData2(Image_Data[i]);
            // DEV_Digital_Write(EPD_CS_PIN, 1);
        }
        else if (color == 1)
        {
            // DEV_Digital_Write(EPD_DC_PIN, 1);
            // DEV_Digital_Write(EPD_CS_PIN, 0);
            EPD_2IN9B_Z94_SendData2(Image_Data[i]);
            // DEV_Digital_Write(EPD_CS_PIN, 1);
        }
    }
#endif   
    // }
}
